package com.jinke.api.modules.app.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellExtraTypeEnum;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.alibaba.excel.read.builder.ExcelReaderSheetBuilder;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.jinke.api.common.api.CommonResult;
import com.jinke.api.common.exception.Asserts;
import com.jinke.api.modules.app.config.PriceRuleImportListener;
import com.jinke.api.modules.app.config.PriceRuleSheetImportListener;
import com.jinke.api.modules.app.config.PriceSurchargeImportListener;
import com.jinke.api.modules.app.config.PriceSurchargeSheetImportListener;
import com.jinke.api.modules.app.controller.res.PriceRuleImportDto;
import com.jinke.api.modules.app.controller.res.PriceSurchargeImportDto;
import com.jinke.api.modules.app.controller.res.RuleSurchargeImportDto;
import com.jinke.api.modules.app.model.PriceRule;
import com.jinke.api.modules.app.mapper.PriceRuleMapper;
import com.jinke.api.modules.app.model.PriceSurcharge;
import com.jinke.api.modules.app.service.PriceRuleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jinke.api.modules.app.service.PriceSurchargeService;
import com.jinke.api.modules.third.ezeeship.model.request.EstimateRateRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 自定义价格表 服务实现类
 * </p>
 *
 * @author macro
 * @since 2024-07-17
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PriceRuleServiceImpl extends ServiceImpl<PriceRuleMapper, PriceRule> implements PriceRuleService {

    private final PriceRuleImportListener priceRuleImportListener;
    private final PriceRuleSheetImportListener priceRuleSheetImportListener;
    private final PriceSurchargeSheetImportListener priceSurchargeSheetImportListener;

    private final PriceSurchargeService priceSurchargeService;

    private static final String XLS = "xls";
    private static final String XLSX = "xlsx";
    private static final String SPLIT = ".";
    /**
     * @Author: hhp
     * @Description: 导入自定义价格表
     * @Data: 2024/7/30 11:43
     * @param  importDto 导入实体
     * @return: com.jinke.api.common.api.CommonResult<java.lang.String>
     * @throws: IOException
     **/
    @Override
    public CommonResult<String> importPriceRules(PriceRuleImportDto importDto) throws IOException {

        MultipartFile file = importDto.getFile();
        InputStream inputStream = file.getInputStream();
        // 获取Excel后缀名
        String fileName = file.getOriginalFilename();
        if (StrUtil.isEmpty(fileName) || fileName.lastIndexOf(SPLIT) < 0) {
            Asserts.fail("解析Excel失败, 因为获取到的Excel文件名非法!");
        }
        // 文件类型
        String fileType = fileName.substring(fileName.lastIndexOf(SPLIT) + 1);
        if (!fileType.equalsIgnoreCase(XLS) && !fileType.equalsIgnoreCase(XLSX)) {
            Asserts.fail("上传文件类型错误, 请上传xls或xlsx格式的文件");
        }

        ExcelReaderBuilder excelReaderBuilder = EasyExcel.read(inputStream, PriceRuleImportDto.PriceRuleItem.class, priceRuleImportListener);
        ExcelReaderSheetBuilder sheet = excelReaderBuilder.sheet().headRowNumber(2);// 表头有2行
        List<PriceRuleImportDto.PriceRuleItem> list = sheet.doReadSync();
        // 重置index
        priceRuleImportListener.setCurIndex(0);

        if (CollectionUtil.isEmpty(list)) {
            Asserts.fail("未检测到任何数据");
        }

        List<PriceRule> savePriceRuleList = Lists.newArrayList();

        StringBuilder errMsg = new StringBuilder();
        for (int i = 0; i < list.size(); i++) {
            PriceRuleImportDto.PriceRuleItem priceRuleItem = list.get(i);

            if (ObjectUtil.isEmpty(priceRuleItem.getZone1()) && ObjectUtil.isEmpty(priceRuleItem.getZone2())
                    && ObjectUtil.isEmpty(priceRuleItem.getZone3()) && ObjectUtil.isEmpty(priceRuleItem.getZone4())
                    && ObjectUtil.isEmpty(priceRuleItem.getZone5()) && ObjectUtil.isEmpty(priceRuleItem.getZone6())
                    && ObjectUtil.isEmpty(priceRuleItem.getZone7())) {
                errMsg.append(StrUtil.format("第{}条数据导入失败，原因：zone1-zone7全部为空", i + 1));
                continue;
            }

            PriceRule priceRule = new PriceRule();
            BeanUtils.copyProperties(priceRuleItem, priceRule);
            /*priceRule.setChannelId();
            priceRule.setServiceCode(importDto.getServiceCode());
            priceRule.setChannelPlatformId();*/
            // 暂时只要serviceCode  channelId和ChannelPlatformId不管
            priceRule.setServiceCode(importDto.getServiceCode());
            // TODO 磅和盎司设置值
            priceRule.setPoundsLine(0);
            priceRule.setOzLine(0);
            savePriceRuleList.add(priceRule);
        }

        if (CollectionUtil.isNotEmpty(savePriceRuleList)) {
            boolean result = this.saveBatch(savePriceRuleList);
            Assert.isTrue(result, "导入数据失败，原因：保存自定义价格表出错");
            if (!result) {
                Asserts.fail("保存价格表失败");
            }
        }

        errMsg.append(StrUtil.format("一共{}条数据，成功导入{}条数据，导入失败数据{}条", list.size(), savePriceRuleList.size(), list.size() - savePriceRuleList.size()));
        return CommonResult.success(errMsg.toString());
    }

    /**
     * 从自定义价格表查价格
     *
     * @param
     */
    @Override
    public PriceRule getRateFromPriceRule(EstimateRateRequest.Parcel parcel) {
        //查价格表
        LambdaQueryWrapper<PriceRule> queryWrapper=new LambdaQueryWrapper();

        String weight = parcel.getWeight();
        String weight2 = parcel.getWeight2();
        int poundPart;
        if (parcel.getMassUnit().equals("kg")){
            double v = 2.2046226 * Double.valueOf(weight);
            int totalOunces = (int) (v* 16);
            poundPart = totalOunces / 16;

            double v1 = Double.valueOf(weight2) / 28.34952;
            weight2=v1+"";
        }else {
            int totalOunces = (int) (Double.valueOf(weight) * 16);
            poundPart = totalOunces / 16;
        }
        if (poundPart==0){
            //只有小数部分
            queryWrapper
                    .eq(PriceRule::getPoundsLine,0)
                    .ge(PriceRule::getOzLine, weight2)
                    .orderByAsc(PriceRule::getId)
                    .last("limit 1")
            ;
        }else {
            //都有
            queryWrapper.
                    le(PriceRule::getPoundsLine, poundPart)
                    .orderByDesc(PriceRule::getId)
                    .last("limit 1")
            ;
        }
        PriceRule one = this.getOne(queryWrapper);
        return one;
    }

    @Override
    @Transactional
    public CommonResult<String> importRuleSurcharge(RuleSurchargeImportDto importDto) throws IOException {
        MultipartFile file = importDto.getFile();
        InputStream inputStream = file.getInputStream();
        // 获取Excel后缀名
        String fileName = file.getOriginalFilename();
        if (StrUtil.isEmpty(fileName) || fileName.lastIndexOf(SPLIT) < 0) {
            Asserts.fail("解析Excel失败, 因为获取到的Excel文件名非法!");
        }
        // 文件类型
        String fileType = fileName.substring(fileName.lastIndexOf(SPLIT) + 1);
        if (!fileType.equalsIgnoreCase(XLS) && !fileType.equalsIgnoreCase(XLSX)) {
            Asserts.fail("上传文件类型错误, 请上传xls或xlsx格式的文件");
        }

        ExcelReader excelReader = EasyExcel.read(inputStream).build();
        // 这里为了简单 所以注册了 同样的head 和Listener 自己使用功能必须不同的Listener
        ReadSheet readSheet1 =
                EasyExcel.readSheet(0).head(RuleSurchargeImportDto.PriceRuleItem.class).headRowNumber(2).registerReadListener(priceRuleSheetImportListener).build();
        ReadSheet readSheet2 =
                EasyExcel.readSheet(1).head(RuleSurchargeImportDto.PriceSurchargeItem.class).headRowNumber(1).registerReadListener(priceSurchargeSheetImportListener).build();
        // 这里注意 一定要把sheet1 sheet2 一起传进去，不然有个问题就是03版的excel 会读取多次，浪费性能
        excelReader.read(readSheet1, readSheet2);

        List<RuleSurchargeImportDto.PriceRuleItem> priceRuleList = priceRuleSheetImportListener.getPriceRuleItems();
        List<RuleSurchargeImportDto.PriceSurchargeItem> priceSurchargeList = priceSurchargeSheetImportListener.getPriceSurchargeItems();
        // 读完重置
        priceRuleSheetImportListener.setCurIndex(0);
        priceRuleSheetImportListener.setPriceRuleItems(Lists.newArrayList());
        priceSurchargeSheetImportListener.setCurIndex(0);
        priceSurchargeSheetImportListener.setPriceSurchargeItems(Lists.newArrayList());

        // 这里可以不做限制 如果第一个sheet是按标准价格表模板导入,第二个sheet不传也可以
        if (CollectionUtil.isEmpty(priceRuleList)) {
            Asserts.fail("第一个sheet未检测到任何数据");
        }
        if (CollectionUtil.isEmpty(priceSurchargeList)) {
            Asserts.fail("第二个sheet未检测到任何数据");
        }

        List<PriceRule> savePriceRuleList = Lists.newArrayList();

        StringBuilder allMsg = new StringBuilder();

        StringBuilder priceRuleMsg = new StringBuilder();
        for (int i = 0; i < priceRuleList.size(); i++) {
            RuleSurchargeImportDto.PriceRuleItem priceRuleItem = priceRuleList.get(i);

            if (ObjectUtil.isEmpty(priceRuleItem.getZone1()) && ObjectUtil.isEmpty(priceRuleItem.getZone2())
                    && ObjectUtil.isEmpty(priceRuleItem.getZone3()) && ObjectUtil.isEmpty(priceRuleItem.getZone4())
                    && ObjectUtil.isEmpty(priceRuleItem.getZone5()) && ObjectUtil.isEmpty(priceRuleItem.getZone6())
                    && ObjectUtil.isEmpty(priceRuleItem.getZone7())) {
                priceRuleMsg.append(StrUtil.format("第{}条数据导入失败，原因：zone1-zone7全部为空", i + 1));
                continue;
            }

            PriceRule priceRule = new PriceRule();
            BeanUtils.copyProperties(priceRuleItem, priceRule);
            /*priceRule.setChannelId();
            priceRule.setServiceCode(importDto.getServiceCode());
            priceRule.setChannelPlatformId();*/
            // 暂时只要serviceCode  channelId和ChannelPlatformId不管
            priceRule.setServiceCode(importDto.getServiceCode());
            // TODO 磅和盎司设置值
            priceRule.setPoundsLine(0);
            priceRule.setOzLine(0);
            savePriceRuleList.add(priceRule);
        }

        if (CollectionUtil.isNotEmpty(savePriceRuleList)) {
            boolean result = this.saveBatch(savePriceRuleList);
            Assert.isTrue(result, "导入数据失败，原因：保存自定义价格表出错");
            if (!result) {
                Asserts.fail("保存价格表失败");
            }
        }

        priceRuleMsg.append(StrUtil.format("一共{}条数据，成功导入{}条数据，导入失败数据{}条", priceRuleList.size(), savePriceRuleList.size(), priceRuleList.size() - savePriceRuleList.size()));
        priceRuleMsg.insert(0, "第一个sheet导入信息:");

        List<PriceSurcharge> savePriceSurchargeList = Lists.newArrayList();
        StringBuilder priceSurchargeMsg = new StringBuilder();
        for (int i = 0; i < priceSurchargeList.size(); i++) {
            // TODO 校验数据... 如果步校验可以在listener里面处理数据，不需要再这里再遍历一遍
            RuleSurchargeImportDto.PriceSurchargeItem priceSurchargeItem = priceSurchargeList.get(i);

            if (StrUtil.isNotBlank(priceSurchargeItem.getZones())) {
                String zones = priceSurchargeItem.getZones();
                if (zones.contains("-")) {
                    priceSurchargeItem.setZones(zones.replaceAll("-", ","));
                    /*priceRuleItem.setZones(Arrays.stream(zones.split("-")).map(item -> {
                        return "zone" + item;
                    }).collect(Collectors.joining(",")));*/
                }
                zones = priceSurchargeItem.getZones();
                if (zones.contains("7+")) {
                    // + 是正则特殊字符 需要用\\转义一下
                    priceSurchargeItem.setZones(zones.replaceAll("7\\+", "7,8,9"));
                }
            }

            PriceSurcharge priceSurcharge = new PriceSurcharge();
            BeanUtils.copyProperties(priceSurchargeItem, priceSurcharge);
            // 取excel表里的serviceCode 不将每一项设置成 页面传过来的serviceCode
            //priceSurcharge.setServiceCode(importDto.getServiceCode());
            savePriceSurchargeList.add(priceSurcharge);
        }
        if (CollectionUtil.isNotEmpty(savePriceSurchargeList)) {
            boolean result = priceSurchargeService.saveBatch(savePriceSurchargeList);
            if (!result) {
                Asserts.fail("保存附加费表失败");
            }
        }
        priceSurchargeMsg.append(StrUtil.format("一共{}条数据，成功导入{}条数据，导入失败数据{}条; ", priceSurchargeList.size(), savePriceSurchargeList.size(), priceSurchargeList.size() - savePriceSurchargeList.size()));
        priceSurchargeMsg.insert(0, "第二个sheet导入信息:");

        allMsg.append(priceRuleMsg);
        allMsg.append(priceSurchargeMsg);
        return CommonResult.success(allMsg.toString());
    }


}
